package com.leezk.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.leezk.order.dto.OrderDto;
import com.leezk.order.entity.Orders;
import com.leezk.order.mapper.OrdersMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.function.Function;


/**
 * @author 小童
 * @version 1.0
 * @date 2022-03-25
 */
@Component
public class StudentLikeService {

    /**
     * 存储计算之后用户的相似度
     * map key-value
     * 用户一：菜单1，菜单2，菜单3
     * 用户二：菜单1，菜单4
     * result： 用户一{用户二：相似度}
     *
     */
    private final HashMap<Integer,Map<Integer,Double>> result=new HashMap<>();

    /**
     * 存储的是每个用户所购买过的菜单
     * 用户一：{菜单1，菜单2，菜单3}
     * 用户二：{菜单1，菜单4}
     */
    private final HashMap<Integer, HashSet<Integer>> studentMenus=new HashMap<>();

    private final OrdersMapper ordersMapper;

    @Autowired
    public StudentLikeService(OrdersMapper ordersMapper) {
        this.ordersMapper = ordersMapper;
    }

    /**
     * 数据库中的订单记录 全部取出来 然后进行计算
     */
    @Async
    @PostConstruct
    public  void initResult(){
        //获取所有订单
        List<Orders> ordersList = ordersMapper.selectList(null);
        //按照用户分类
        for (Orders orders : ordersList) {
            List<OrderDto.OrderChild> orderChildren = JSON.parseArray(orders.getDeail(), OrderDto.OrderChild.class);
            Integer sid=orders.getSid();
            if (!studentMenus.containsKey(sid)){
                studentMenus.put(sid,new HashSet<>());
            }
            for (OrderDto.OrderChild orderChild : orderChildren) {
                studentMenus.get(sid).add(orderChild.getId());
            }
        }
        System.out.println("*******************订单按照用户分类**********************");
        studentMenus.forEach((k,v)->{
            System.out.println(k+":"+v);
        });
        System.out.println("*****************************************");
        //获取有订单的用户
        Set<Integer> studentList = studentMenus.keySet();
        BiFunction<Set<Integer>,Object,Integer> getExistNum=(set,obj)->{return set.contains(obj)?1:0;};
        //计算相似度
        for (Integer firstStudent : studentList) {
            result.put(firstStudent,new HashMap<>());
            for (Integer secondStudent : studentList) {
                if (firstStudent.equals(secondStudent)){
                    continue;
                }
                HashSet<Integer> firstMenus = studentMenus.get(firstStudent);
                HashSet<Integer> secondMenus = studentMenus.get(secondStudent);
                Set<Object> unite = this.getUnite(firstMenus, secondMenus);
                int molecular=0;
                double denominator=0;
                double first=0.0;
                double second=0.0;
                for (Object o : unite) {
                    molecular+=getExistNum.apply(firstMenus,o)*getExistNum.apply(secondMenus,o);
                    first+=Math.pow(getExistNum.apply(firstMenus,o),2);
                    second+=Math.pow(getExistNum.apply(secondMenus,o),2);
                }
                denominator=Math.sqrt(first)+Math.sqrt(second);
                double similarity=molecular/denominator;
                result.get(firstStudent).put(secondStudent,similarity);
            }
        }
        System.out.println(studentMenus);
        System.out.println(result);
    }

    public Set<Integer> getMenus(int studentId,Double base){
        Set<Integer> menus=new HashSet<>();
       if (result.containsKey(studentId)){
           Map<Integer, Double> integerDoubleMap = result.get(studentId);
           integerDoubleMap.forEach((k,v)->{
               System.out.println(k!=studentId);
               System.out.println(v-base);
               if (k!=studentId&&v>=base){
                   menus.addAll(studentMenus.get(k));
               }
           });
       }
       if (studentMenus.containsKey(studentId)){
           menus.addAll(studentMenus.get(studentId));
       }
       return menus;
    }

    /**
     * 求并集
     */
    private Set<Object> getUnite(Set<?> set1, Set<?> set2) {

        Set<Object> set = new HashSet<>();

        set.addAll(set1);
        set.addAll(set2);

        return set;
    }


}
